package ms.unicorn.modellanguage;

import java.util.ArrayList;
import java.util.List;

import ms.unicorn.EPhantomAttribute;
import ms.unicorn.language.languagedef.ElementDef;
import ms.unicorn.language.languagedef.TagDef;
import ms.unicorn.language.languagedef.TagDefUtil;
import ms.unicorn.language.languagedef.TagEntryDef;
import ms.unicorn.util.ReflectionUtil;

import org.eclipse.emf.common.util.ResourceLocator;
import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
import org.eclipse.gmf.runtime.emf.type.core.ElementTypeRegistry;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.IHintedType;
import org.eclipse.gmf.runtime.emf.type.core.ISpecializationType;

public abstract class LanguageElement {
	
	private IElementType elementType;
	private IModelLanguage language;
	private ElementDef def;
	private List<IItemPropertyDescriptor> propertyDescriptors;
	
	protected LanguageElement(IModelLanguage language, ElementDef definition) {
		this.language = language;
		def = definition;
		String helperClassName = def.getHelper();
		if (helperClassName != null) {
			IElementEditHelperAdvice advice = (IElementEditHelperAdvice) language.getCachedObject(helperClassName);
			if (advice == null) {
				Class<?> clazz = ReflectionUtil.getClass(helperClassName);
				if (clazz !=  null) {
					try {
						advice = (IElementEditHelperAdvice) clazz.newInstance();
						language.setCachedObject(advice);
					} catch (Exception e) {
						e.printStackTrace();
					} 
				}
			}
			setEditHelperAdvice(advice);
		}
	}
	
	protected ISpecializationType createElementType() {
		HintedSpecializationType result = (HintedSpecializationType) ElementTypeRegistry.getInstance().getType(getId());
		IElementType baseType = getBaseType();
		if (result == null)
				result = new HintedSpecializationType(
					getId(), null, getName(), 
					new IElementType[] {baseType},
					null, 
					null, 
					getEditHelperAdvice());
		result.setElement(this);
		result.setLanguage(language);
		result.setSemanticHint(((IHintedType) baseType).getSemanticHint());
		return result;
	}
	
	public boolean acceptChild(LanguageElement element) {
		return false;
	}
	
	protected IElementType getBaseType() {
		return null;
	}
	
	public ElementDef getDefinition(){
		return def;
	}
	
	public String getId() {
		return language.getId() + "." +  def.getName();
	}

	public String getName() {
		return def.getText();
	}

	public void setEditHelperAdvice(IElementEditHelperAdvice advice) {
		
	}

	public IElementEditHelperAdvice getEditHelperAdvice() {
		return null;
	}

	public void setElementType(IElementType elementType) {
		this.elementType = elementType;
	}

	public IElementType getElementType() {
		return elementType != null ? elementType : (elementType = createElementType());
	}

	public IModelLanguage getLanguage() {
		return this.language;
	}

	public List<IItemPropertyDescriptor> getPropertyDescriptors(ComposeableAdapterFactory composeableAdapterFactory, 
			ResourceLocator resourceLocator, List<IItemPropertyDescriptor> list) {
		if (propertyDescriptors ==  null) {
			propertyDescriptors = new ArrayList<IItemPropertyDescriptor>(list);
			TagDef fields = TagDefUtil.getTagDef(def, "fields");
			if (fields != null)
				for(TagEntryDef field: fields.getEntry()) {
					EPhantomAttribute attr = (EPhantomAttribute) TagDefUtil.getEAttribute(field);
					if (attr != null)
						propertyDescriptors.add	(new ItemPropertyDescriptor
							(composeableAdapterFactory,
							 resourceLocator,
							 attr.getDisplayName(),
							 attr.getDescription(),
							 attr,
							 attr.isChangeable(),
							 attr.isMultiLine(),
							 attr.isSortChoice(),
							 attr.getImage(),
							 attr.getCategory(),
							 null));
				}
				
		}
		return propertyDescriptors;
	}
	
}
